package com.xcrj.java8.lambda;

import java.util.List;
import java.util.ArrayList;
/**
 * lambda表达式，函数作为方法入参
 * xcrj 有函数式接口才能使用lambda，有lambda才能使用方法引用
 * xcrj lambda表达式是一种函数式接口 interface上标注@FunctionalInterface
 * xcrj lambda表达式是实现了接口的匿名内部类
 * lambda表达式实现了interface中定义的方法，lambda表达式与匿名内部类相关，简化了以前匿名类的写法
 * 
 * lambda表达式原理：参考，https://xie.infoq.cn/article/f859764824f443776bc95fd1e
 * - 运行时生成了接口的匿名内部类，实现的方法调用了外部类中生成的静态方法
 * - 运行时在外部类中生成了静态方法，lambda表达式做方法体
 * 
 * xcrj lambda表达式中只能使用final含义的变量（后面不会再被修改的变量）
 * - 显式final修饰
 * - 隐式不被修改
 * 原因：lambda表达式最终成了外部类中的静态方法
 * 
 * xcrj functional interface 只能有1个方法
 */
public class Test1 {
    public static void test1(PingPong pingPong){
       pingPong.pong();
    }
    
    public static void test2(double a,double b,QuadricOperation quadricOperation){
        System.out.println(quadricOperation.operate(a, b));
    }

    public static void main(String[] args) {
        // 无入参，无返回值
        PingPong pingPong=()->System.out.println("pong");
        test1(pingPong);

        // xcrj 几种书写方式
        // 有入参，有返回值
        QuadricOperation add=(double a,double b)->{return a+b;};
        QuadricOperation sub=(a,b)->{return a-b;};
        QuadricOperation mul=(double a,double b)->a*b;
        QuadricOperation div=(a,b)->a/b;

        test2(10.0,2.0,add);
        test2(10.0,2.0,sub);
        test2(10.0,2.0,mul);
        test2(10.0,2.0,div);

        // lambda表达式中只能使用final含义的变量
        // 显式final修饰
        final int v=10;
        PingPong pingPong1=()->System.out.println(v);
        test1(pingPong1);

        // 隐式不被修改
        int v2=20;
        PingPong pingPong2=()->System.out.println(v2);
        test1(pingPong2);

        // 被修改，编译报错
        int v3=30;
        PingPong pingPong3=()->System.out.println(v3);
        test1(pingPong3);
        // v3被修改
        // v3=10;

        // 隐式不被修改，list对象未改变
        List<String> list=new ArrayList<>();
        list.add("a");
        PingPong pingPong4=()->System.out.println(list);
        test1(pingPong4);
        list.add("b");

        // 隐式不被修改，list对象未改变
        List<String> list2=new ArrayList<>();
        list2.add("a");
        PingPong pingPong5=()->System.out.println(list2);
        test1(pingPong5);
        // list2被修改
        // list2=new ArrayList<>();
    }
}
